package com.awx.client.navigation;

import java.awt.Dimension;
import java.awt.Toolkit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

import com.awx.client.exception.AwxClientException;
import com.awx.client.navigation.menu.AwxMenuConfiguration;
import com.sun.java.swing.plaf.windows.WindowsLookAndFeel;

public abstract class AwxController extends JFrame {

	private JMenuBar menuBar;
	private JDesktopPane desktop;
	private Dimension userWindowSize;
	private Map<String, AwxWindow> windows;
	private List<AwxWindow> visibleWindows;
	private Map<String, Object> clientContext;
	private AwxApplication application;


	public AwxController() {
		this.clientContext = new HashMap<String, Object>();

		this.configureSize();
		this.configureAppereance();
		this.createDesktop();
		this.setupRegisteredWindows();

	}

	public void startUp() {
		this.createMenuBar();
		this.setVisible( true );
		this.showFirstWindow();
	}

	private void showFirstWindow() {
		String window = this.getFirstWindow();
		if( window != null ) {
			this.showWindow( window );
		}
	}

	/**
	 * Set the first window to show once the main menu is loaded.
	 * If there is no first window, return null.
	 * @return first window or null
	 */
	protected abstract String getFirstWindow();

	private void createMenuBar() {
		//check user access
		this.setJMenuBar( this.getMenuConfiguration().buildMenuBar( this ) );
	}

	protected AwxMenuConfiguration getMenuConfiguration() {
		return this.application.getMenuConfiguration();
	}


	private void createDesktop() {
		this.desktop = new JDesktopPane();
		this.desktop.setVisible( true );
		this.getContentPane().add( desktop );
		this.setDefaultCloseOperation( DISPOSE_ON_CLOSE );

	}

	private void configureSize() {
		this.userWindowSize = Toolkit.getDefaultToolkit().getScreenSize();
		this.setSize( this.userWindowSize );
		this.setExtendedState( MAXIMIZED_BOTH );
	}

	private void configureAppereance() {
		try {
    		UIManager.setLookAndFeel( new WindowsLookAndFeel() );
    	} catch (UnsupportedLookAndFeelException ex) {
    		throw new AwxClientException( "Error stting XP look and feel", ex );
    	}
    	SwingUtilities.updateComponentTreeUI( this );
	}

	private void setupRegisteredWindows() {
		this.windows = new HashMap<String, AwxWindow>();
		this.visibleWindows = new ArrayList<AwxWindow>();
		this.registerWindows();
	}


	protected abstract void registerWindows();


	public void addWindow( String winName, AwxWindow window ) {
		if( this.hasWindow(winName) ) {
			throw new AwxClientException( "There is already a window with the name: " + winName );
		} else {
			this.windows.put( winName, window );
			window.setVisible( false );
			this.desktop.add( window );
			window.setController( this );
		}
	}

	public void removeWindow( String winName ) {
		if( this.hasWindow(winName) ) {
			AwxWindow window = this.windows.remove( winName );
			this.desktop.remove( window );
		} else {
			throw new AwxClientException( "It does not exist a window with name: " + winName );
		}
	}

	public void removeAllWindows() {
		this.windows.clear();
	}

	public boolean hasWindow( String winName ) {
		return this.windows.containsKey( winName );
	}

	public void showWindow( String winName ) {
		if( hasWindow(winName) ) {
			AwxWindow window = this.windows.get( winName );
			this.makeWindowVisible( window );

		} else {
			throw new AwxClientException( "It does not exist a window with name: " + winName );
		}
	}

	public void showWindowOnly( String winName ) {
		this.hideAllWindows();
		this.showWindow( winName );
	}

	public void hideWindow( String winName ) {
		if( hasWindow(winName) ) {
			AwxWindow window = this.windows.get( winName );
			this.makeWindowHidden( window );
		} else {
			throw new AwxClientException( "It does not exist a window with name: " + winName );
		}
	}

	public void hideAllWindows() {
		for (AwxWindow win : this.visibleWindows) {
			win.setVisible( false );
			win.onHide();
		}
		this.visibleWindows.removeAll( this.visibleWindows );
	}

	public void windowHidden(AwxWindow window) {
		this.visibleWindows.remove( window );
		window.setVisible( false );
		window.onHide();
	}

	private void makeWindowVisible(AwxWindow window) {
		if( !this.isWindowVisible(window) ) {
			this.visibleWindows.add( window );
			window.setLocation( userWindowSize.width / 2 - window.getWidth() / 2, 0 );
			window.onBeforeShow();
			window.setVisible( true );
			window.onShow();
		}
	}

	private void makeWindowHidden( AwxWindow window ) {
		if( this.isWindowVisible(window) ) {
			this.visibleWindows.remove( window );
			window.setVisible( false );
			window.onHide();
		}
	}

	public boolean isWindowVisible( AwxWindow window ) {
		return this.visibleWindows.contains( window );
	}


	public void addToClientContext( String key, Object value ) {
		this.clientContext.put(key, value);
	}

	public void removeFromClientContext( String key ) {
		this.clientContext.remove( key );
	}

	public Object getFromClientContext( String key ) {
		return this.clientContext.get( key );
	}

	public void clearClientContext() {
		this.clientContext.clear();
	}

	protected AwxApplication getApplication() {
		return application;
	}

	public void setApplication(AwxApplication application) {
		this.application = application;
	}



}



















